// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;

#include "Symbole.h"
#include "Valeur.h"
class LecteurFonction;
////////////////////////////////////////////////////////////////////////////////
class Noeud {
// classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
// Remarque : la classe ne contient aucun constructeur
  public:
    virtual Valeur* getValeur() =0 ; // méthode pure (non implémentée) qui rend la classe abstraite
    virtual void afficher(unsigned short indentation=0) { cout << setw(4*indentation) << " "; }
      // pour afficher un noeud avec un décalage (indentation) proportionnel à son niveau dans l'arbre
    virtual string getCpp()=0; //retourne l'equivalent en Cpp du noeud
    virtual ~Noeud() {} // présence d'un destructeur virtuel conseillée dans les classes abstraites
};

////////////////////////////////////////////////////////////////////////////////
class NoeudSeqInst : public Noeud {
// classe pour représenter un noeud "sequence d'instruction"
// qui a autant de fils que d'instructions dans la séquence
  public:
     NoeudSeqInst();   // construit une séquence d'instruction vide
    ~NoeudSeqInst() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation=0); // affiche la séquence d'instructions
    void ajouteInstruction(Noeud* instruction);  // ajoute une instruction à la séquence
    inline void setRetour (Noeud * r) { retour=r;}
    string getCpp(); //retourne l'equivalent en Cpp du noeud

  private:
      Noeud* retour; //utilisé uniquement dans les fonctions
    vector<Noeud *> tabInst; // pour stocker les instructions de la séquence
};
////////////////////////////////////////////////////////////////////////////////
class NoeudFonction : public Noeud {
// classe pour représenter un noeud "declaration de fonction"
  public:
     NoeudFonction(string nom,vector<LecteurFonction *> tf);   // construit une fonction vide
    ~NoeudFonction() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation=0); // affiche la fonction
    void ajouteParametre(Noeud* exp);  // ajoute une variable à la sequence
    inline void setFonction(LecteurFonction * fonc) { fonction=fonc;} //setteur
    string getCpp(); //retourne l'equivalent en Cpp du noeud

  private:
    vector<Noeud *> tabPar; // pour stocker les parametres de la fonction
    LecteurFonction* fonction;
};
////////////////////////////////////////////////////////////////////////////////
class NoeudAffectation : public Noeud {
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
  public:
     NoeudAffectation(Noeud* variable, Noeud* expression); // construit une affectation
    ~NoeudAffectation() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation
    string getCpp(); //retourne l'equivalent en Cpp du noeud

  private:
    Noeud* variable;
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurBinaire : public Noeud {
// classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
  public:
    NoeudOperateurBinaire(Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit);
     // construit une opération binaire : operandeGauche operateur OperandeDroit
   ~NoeudOperateurBinaire() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération
    string getCpp(); //retourne l'equivalent en Cpp du noeud
    Symbole* getOp(); //retourne l'operateur du noeud
    
  private:
    Symbole operateur;
    Noeud*  operandeGauche;
    Noeud*  operandeDroit;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstSi : public Noeud {
    
public:
    NoeudInstSi(Noeud* expBool, Noeud* SeqInst, NoeudInstSi* Sinon);
    ~NoeudInstSi() {}
    Valeur* getValeur(); // évalue la condition et renvoie soit la séquence d'instruction, soit le sinon
    inline Noeud* getCond() { return this->sinon;};
    void afficher(unsigned short indentation=0); // affiche l'opération
    inline NoeudInstSi* setSinon(Noeud* expBool, Noeud* seqInst) { this->sinon=new NoeudInstSi(expBool,seqInst,NULL); return this->sinon; };
    string getCpp(); //retourne l'equivalent en Cpp du noeud
private:
    //arbre contenant :
    //-expBool (expression du si)
    //-seqInst (Instructions du si)
    //-sinon (Noeud sinon)
    Noeud* expBool;
    Noeud* seqInst;
    NoeudInstSi* sinon;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstLoop : public Noeud { //classe abstraite pour tantque, pour, repeter
public:
    NoeudInstLoop(Noeud* expBool, Noeud* SeqInst);
    virtual ~NoeudInstLoop() {}
    virtual Valeur* getValeur()=0; 
    virtual void afficher(unsigned short indentation=0, string message=""); 
    inline Noeud* getCond() { return this->expBool; };
    inline Noeud* getSeq() { return this->seqInst; };
    virtual string getCpp()=0; //retourne l'equivalent en Cpp du noeud
    
    
private:
    Noeud* expBool;
    Noeud* seqInst;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstTantque : public NoeudInstLoop {
public:
    NoeudInstTantque(Noeud* expBool, Noeud* SeqInst);
    ~NoeudInstTantque() {}
    Valeur* getValeur(); 
    void afficher(unsigned short indentation=0); 
    string getCpp(); //retourne l'equivalent en Cpp du noeud
    
private:
    
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstRepeter : public NoeudInstLoop {
public:
    NoeudInstRepeter(Noeud* expBool, Noeud* SeqInst);
    ~NoeudInstRepeter() {}
    Valeur* getValeur(); 
    void afficher(unsigned short indentation=0); 
    string getCpp(); //retourne l'equivalent en Cpp du noeud
    
private:
    
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstPour : public NoeudInstLoop {
public:
    NoeudInstPour(Noeud* expBool, Noeud* SeqInst,Noeud* init, Noeud* iter);
    ~NoeudInstPour() {}
    Valeur* getValeur(); 
    void afficher(unsigned short indentation=0);
    string getCpp(); //retourne l'equivalent en Cpp du noeud
    
private:
    Noeud* init;
    Noeud* iter;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstLire : public Noeud {
public:
    NoeudInstLire(Noeud* var);
    ~NoeudInstLire() {}
    Valeur* getValeur();
    void afficher(unsigned short indentation=0);
    string getCpp(); //retourne l'equivalent en Cpp du noeud
    
private:
    Noeud* var;
};

////////////////////////////////////////////////////////////////////////////////

class NoeudInstEcrire : public Noeud {
public:
    NoeudInstEcrire(Noeud* var);
    ~NoeudInstEcrire() {}
    Valeur* getValeur();
    void afficher(unsigned short indentation=0);
    string getCpp(); //retourne l'equivalent en Cpp du noeud
private:
    Noeud* var;
};
////////////////////////////////////////////////////////////////////////////////

class NoeudInstCase : public Noeud {
public:
    NoeudInstCase(Noeud* val, Noeud* seqInst,bool def);
    Valeur* getValeur(); //retourne la valeur de la sequence d'instruction
    Valeur* getVal(); //retourne la valeur de la condition
    void afficher(unsigned short indentation=0);
    string getCpp(); //retourne l'equivalent en Cpp du noeud
    bool isDefault() {return _default;}
private:
    Noeud* val;
    Noeud* seqInst;
    bool _default;
};


class NoeudInstSwitch : public Noeud {
public:
    NoeudInstSwitch(Noeud* var);
    void ajouteCase(NoeudInstCase* _case);
    Valeur* getValeur();
    void afficher(unsigned short indentation=0);
    string getCpp(); //retourne l'equivalent en Cpp du noeud
private:
    Noeud* var;
    vector<NoeudInstCase*> tabCase;
};

#endif /* ARBRE_H_ */
